package com.jh.user.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.google.common.base.Charsets;
import com.google.common.collect.*;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.util.*;
import java.util.concurrent.ConcurrentMap;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.nio.file.StandardOpenOption.*;


/**
 * JSON 工具类。
 *
 * @author Fuchun
 * @since 1.0
 * @deprecated use matrix-core module {@link com.huishu.common.json.JsonKt}
 */
@Deprecated
public class JsonKt {
//
//    private static final OpenOption[] DEFAULT_OPEN_OPTIONS = { WRITE, CREATE, TRUNCATE_EXISTING };
//    private static final ImmutableClassToInstanceMap<Collection<?>> COLLECTIONS =
//            new ImmutableClassToInstanceMap.Builder<Collection<?>>()
//                    .put(List.class, ImmutableList.of())
//                    .put(Set.class, ImmutableSet.of())
//                    .build();
//    private static final Table<Class<?>, Class<?>, Class<?>> MAP_CLASSES = HashBasedTable.create();
//    private static final Map<Class<?>, Class<?>> LIST_CLASSES = Maps.newHashMap();
//    private static final Map<Class<?>, Class<?>> SET_CLASSES = Maps.newHashMap();
//
//    private static Companion companion = new Companion();
//    private static ObjectMapper objectMapper;
//    private static ObjectWriter prettyWriter;
//
//    static {
//        initialize();
//    }
//
//    private static void initialize() {
//        companion.afterPropertiesSet();
//    }
//
//    @SuppressWarnings("unchecked")
//    private static <K, V> Class<Map<K, V>> resolveMapClass(Class<K> keyClass, Class<V> valClass) {
//        Class<?> mc = MAP_CLASSES.get(keyClass, valClass);
//        Class<Map<K, V>> mapClass;
//        if (mc != null) {
//            mapClass = (Class<Map<K, V>>) mc;
//        } else {
//            mapClass = (Class<Map<K, V>>) new TypeToken<Map<K, V>>() {}
//                    .where(new TypeParameter<K>() {}, keyClass)
//                    .where(new TypeParameter<V>() {}, valClass).getRawType();
//            MAP_CLASSES.put(keyClass, valClass, mapClass);
//        }
//        return mapClass;
//    }
//
//    @SuppressWarnings("unchecked")
//    private static <T> Class<List<T>> resolveListClass(Class<T> elementClass) {
//        Class<?> lc = LIST_CLASSES.get(elementClass);
//        Class<List<T>> listClass;
//        if (lc != null) {
//            listClass = (Class<List<T>>) lc;
//        } else {
//            listClass = (Class<List<T>>) new TypeToken<List<T>>() {}
//            .where(new TypeParameter<T>() {}, elementClass).getRawType();
//            LIST_CLASSES.put(elementClass, listClass);
//        }
//        return listClass;
//    }
//
//    @SuppressWarnings("unchecked")
//    private static <T> Class<Set<T>> resolveSetClass(Class<T> elementClass) {
//        Class<?> lc = SET_CLASSES.get(elementClass);
//        Class<Set<T>> setClass;
//        if (lc != null) {
//            setClass = (Class<Set<T>>) lc;
//        } else {
//            setClass = (Class<Set<T>>) new TypeToken<Set<T>>() {}
//                    .where(new TypeParameter<T>() {}, elementClass).getRawType();
//            SET_CLASSES.put(elementClass, setClass);
//        }
//        return setClass;
//    }
//
//    public static <T> T convert(Map<String, Object> map, Class<T> targetClass) {
//        if (map == null) {
//            return null;
//        }
//        if (map.isEmpty()) {
//            try {
//                Constructor<T> c = targetClass.getConstructor();
//                return c.newInstance(); // just new instance
//            } catch (NoSuchMethodException ex) {
//                throw new IllegalArgumentException(String.format(
//                        "The target class %s have no default constructor.", targetClass), ex);
//            } catch (Exception ex) {
//                throw new RuntimeException(ex);
//            }
//        }
//        return doConvert(map, targetClass);
//    }
//
//    @SuppressWarnings("TypeParameterUnusedInFormals")
//    public static <T> T convert(Map<String, Object> map, Type type) {
//        if (map == null) return null;
//        try {
//            return objectMapper.convertValue(map, toJavaType(type));
//        } catch (Exception ex) {
//            throw rethrow(map, type, ex);
//        }
//    }
//
//    private static <T> T doConvert(Map<String, Object> map, Class<T> targetClass) {
//        try {
//            return objectMapper.convertValue(map, targetClass);
//        } catch (Exception ex) {
//            throw rethrow(map, targetClass, ex);
//        }
//    }
//
//    /**
//     * 反序列化一个JSON字符串列表，一个JSON字符串对应一个反序列化对象。如果{@code skipNull == true}，
//     * 在反序列化时，将忽略JSON列表中的{@code null} 和空字符串。
//     * <pre>{@code
//     * List<String> jsonList = Arrays.asList("{\"l\":1,\"r\":2}", null, "{\"l\":3,\"r\":5}");
//     * List<Pair<Integer, Integer>> pairClass = new TypeToken<Pair<Integer, Integer>>(){}.getRawType();
//     * List<Pair<Integer, Integer>> list = JSON.deserialize(jsonList, pairClass, true);
//     * // list.size() == 2
//     * List<Pair<Integer, Integer>> list2 = JSON.deserialize(jsonList, pairClass, false);
//     * // list.size() == 3
//     * }</pre>
//     *
//     * @param jsonList JSON字符串列表。
//     * @param elementType 列表元素类型。
//     * @param skipNull 是否忽略{@code null}和空元素。
//     * @param <E> 元素泛型类型。
//     * @return 返回反序列化后的列表。
//     */
//    @NotNull
//    public static <E> List<E> deserialize(
//            List<String> jsonList, Class<E> elementType, boolean skipNull) {
//        checkArgument(elementType != null, "elementType");
//        if (jsonList == null || jsonList.isEmpty()) {
//            return ImmutableList.of();
//        }
//        List<E> list = new ArrayList<>(jsonList.size());
//        int i = 0;
//        for (String json : jsonList) {
//            if (json == null || json.isEmpty()) {
//                if (skipNull) continue;
//                list.add(i, null);
//            } else {
//                list.add(i, readValue(json, elementType));
//            }
//            i++;
//        }
//        return list;
//    }
//
//    // toJSON xxx methods
//
//    @Contract("null, _, _ -> null")
//    public static String toJSONString(Object object, @Nullable Class<?> viewClass, boolean prettyPrinter) {
//        if (object == null) return null;
//
//        if (viewClass == null) {
//            try {
//                if (prettyPrinter) {
//                    return prettyWriter.writeValueAsString(object);
//                } else {
//                    return objectMapper.writeValueAsString(object);
//                }
//            } catch (JsonProcessingException ex) {
//                throw new JsonException(ex);
//            }
//        }
//        ObjectWriter writer = companion.viewWriters.computeIfAbsent(viewClass, k -> objectMapper.writerWithView(viewClass));
//
//        try {
//            if (prettyPrinter) {
//                return writer.withDefaultPrettyPrinter().writeValueAsString(object);
//            } else {
//                return writer.writeValueAsString(object);
//            }
//        } catch (JsonProcessingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    public static String toJSONString(Object object) {
//        return toJSONString(object, false);
//    }
//
//    public static String toPrettyJSONString(Object object) {
//        return toJSONString(object, true);
//    }
//
//    public static String toJSONString(Object object, boolean prettyPrinter) {
//        return toJSONString(object, null, prettyPrinter);
//    }
//
//    public static String toJSONString(Object object, Class<?> viewClass) {
//        return toJSONString(object, viewClass, false);
//    }
//
//    public static String toPrettyJSONString(Object object, Class<?> viewClass) {
//        return toJSONString(object, viewClass, true);
//    }
//
//    public static byte[] toJSONBytes(Object object, Class<?> viewClass) {
//        if (viewClass == null) {
//            try {
//                return objectMapper.writeValueAsBytes(object);
//            } catch (JsonProcessingException ex) {
//                throw new JsonException(ex);
//            }
//        }
//        ObjectWriter writer = companion.viewWriters.computeIfAbsent(viewClass, k -> objectMapper.writerWithView(viewClass));
//        try {
//            return writer.writeValueAsBytes(object);
//        } catch (JsonProcessingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    public static byte[] toJSONBytes(Object object) {
//        return toJSONBytes(object, null);
//    }
//
//    // write methods
//
//    public static void writeValue(OutputStream output, Object object) throws IOException {
//        writeValue(output, object, false);
//    }
//
//    public static void writeValue(OutputStream output, Object object, boolean prettyPrinter) throws IOException {
//        checkArgument(output != null, "output must be not null");
//        checkArgument(object != null, "object must be not null");
//        try {
//            if (prettyPrinter) {
//                prettyWriter.writeValue(output, object);
//            } else {
//                objectMapper.writeValue(output, object);
//            }
//        } catch (JsonGenerationException | JsonMappingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    public static void writeValue(File out, Object object, OpenOption... options) throws IOException {
//        checkNotNull(out, "file");
//        checkArgument(out.isFile(), "The file(%s) is not a file.", out);
//        OpenOption[] openOptions;
//        if (options == null || options.length == 0) {
//            openOptions = DEFAULT_OPEN_OPTIONS;
//        } else {
//            openOptions = options;
//        }
//        writeValue(Files.newOutputStream(out.toPath(), openOptions), object);
//    }
//
//    // Parse methods
//
//    public static <T> T parseObject(String jsonString, Class<T> targetClass) {
//        return readValue(jsonString, targetClass);
//    }
//
//    public static <T> T parseObject(byte[] data, Class<T> targetClass) {
//        return readValue(new String(data, Charsets.UTF_8), targetClass);
//    }
//
//    @SuppressWarnings("TypeParameterUnusedInFormals")
//    public static <T> T parseObject(String jsonString, Type type) {
//        return readValue(jsonString, toJavaType(type));
//    }
//
//    public static <T> T parseObject(File file, Class<T> targetClass) throws IOException {
//        checkArgument(file != null && file.exists(), "The file must be not null and exists.");
//        checkArgument(file.isFile(), "The file is a directory?");
//        try {
//            return objectMapper.readValue(file, targetClass);
//        } catch (com.fasterxml.jackson.core.JsonParseException | JsonMappingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    @SuppressWarnings("TypeParameterUnusedInFormals")
//    public static <T> T parseObject(File file, Type targetType) throws IOException {
//        checkArgument(file != null && file.exists(), "The file must be not null and exists.");
//        checkArgument(file.isFile(), "The file is a directory?");
//        try {
//            return objectMapper.readValue(file, toJavaType(targetType));
//        } catch (com.fasterxml.jackson.core.JsonParseException | JsonMappingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    public static <T> T parseObject(InputStream input, Class<T> targetClass) throws IOException {
//        try {
//            return objectMapper.readValue(input, targetClass);
//        } catch (com.fasterxml.jackson.core.JsonParseException | JsonMappingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    @SuppressWarnings("TypeParameterUnusedInFormals")
//    public static <T> T parseObject(InputStream input, Type targetType) throws IOException {
//        try {
//            return objectMapper.readValue(input, toJavaType(targetType));
//        } catch (com.fasterxml.jackson.core.JsonParseException | JsonMappingException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    public static <T> List<T> parseToList(String jsonString, Class<T> elementClass) {
//        Class<List<T>> listClass = resolveListClass(elementClass);
//        return parseToCollection(jsonString, listClass, elementClass);
//    }
//
//    @SuppressWarnings("unchecked")
//    public static <T> List<T> parseToList(String jsonString, Type elementType) {
//        Class<List<T>> listClass = (Class<List<T>>) new TypeToken<List<T>>(){}.getRawType();
//        return parseToCollection(jsonString, listClass, elementType);
//    }
//
//    public static <T> Set<T> parseToSet(String jsonString, Class<T> elementClass) {
//        Class<Set<T>> setClass = resolveSetClass(elementClass);
//        return parseToCollection(jsonString, setClass, elementClass);
//    }
//
//    @SuppressWarnings("unchecked")
//    public static <T> Set<T> parseToSet(String jsonString, Type elementType) {
//        Class<Set<T>> setClass = (Class<Set<T>>) new TypeToken<Set<T>>(){}.getRawType();
//        return parseToCollection(jsonString, setClass, elementType);
//    }
//
//    public static <K, V, M extends Map<K, V>> M parseToMap(
//            String jsonString, Class<M> mapClass, Class<K> keyClass, Class<V> valueClass) {
//        if (jsonString == null || jsonString.isEmpty()) {
//            return null;
//        }
//        if ("{}".equals(jsonString)) {
//            return emptyMapInstance(mapClass);
//        }
//        checkArgument(keyClass != null, "keyClass must be not null");
//        checkArgument(valueClass != null, "valueClass must be not null");
//        return doParseToMap(jsonString, mapClass, keyClass, valueClass);
//    }
//
//    public static <K, V> Map<K, V> parseToMap(String jsonString, Type keyType, Type valueType) {
//        if (jsonString == null || jsonString.isEmpty()) {
//            return null;
//        }
//        if ("{}".equals(jsonString)) {
//            return ImmutableMap.of();
//        }
//        checkArgument(keyType != null, "keyType must be not null");
//        checkArgument(valueType != null, "valueType must be not null");
//        return doParseToMap(jsonString, keyType, valueType);
//    }
//
//    public static Map<String, Object> parseToMap(String jsonString) {
//        return parseToMap(jsonString, String.class, Object.class);
//    }
//
//    public static <K, V> Map<K, V> parseToMap(String jsonString, Class<K> keyClass, Class<V> valueClass) {
//        Class<Map<K, V>> mapClass = resolveMapClass(keyClass, valueClass);
//        return parseToMap(jsonString, mapClass, keyClass, valueClass);
//    }
//
//    public static <C extends Collection<T>, T> C parseToCollection(
//            String jsonString, Class<C> listClass, Class<T> elementClass) {
//        if (jsonString == null || jsonString.isEmpty()) {
//            return null;
//        }
//        if ("[]".equals(jsonString)) {
//            return collectionInstance(listClass);
//        }
//        checkArgument(listClass != null, "listClass must be not null");
//        checkArgument(elementClass != null, "elementClass must be not null");
//        return doParseToCollection(jsonString, listClass, elementClass);
//    }
//
//    public static <C extends Collection<T>, T> C parseToCollection(
//            String jsonString, Class<C> colClass, Type elementType) {
//        if (jsonString == null || jsonString.isEmpty()) {
//            return null;
//        }
//        checkArgument(colClass != null, "colClass must be not null");
//        checkArgument(elementType != null, "elementType must be not null");
//        return doParseToCollection(jsonString, colClass, elementType);
//    }
//
//    private static <C extends Collection<?>> C collectionInstance(Class<C> collectionClass) {
//        C c = COLLECTIONS.getInstance(collectionClass);
//        if (c == null) {
//            // use default constructor
//            try {
//                c = collectionClass.getConstructor().newInstance();
//            } catch (Exception ex) {
//                throw new RuntimeException(ex);
//            }
//        }
//        return c;
//    }
//
//    @SuppressWarnings("unchecked")
//    private static <M extends Map<?,?>> M emptyMapInstance(Class<M> mapClass) {
//        if (Map.class.isAssignableFrom(mapClass) || ImmutableMap.class.isAssignableFrom(mapClass)) {
//            return (M) ImmutableMap.of();
//        } else if (SortedMap.class.isAssignableFrom(mapClass) || ImmutableSortedMap.class.isAssignableFrom(mapClass)) {
//            return (M) ImmutableSortedMap.of();
//        } else if (TreeMap.class.isAssignableFrom(mapClass)) {
//            return (M) new TreeMap<>();
//        } else {
//            try {
//                return mapClass.getConstructor().newInstance();
//            } catch (Exception ex) {
//                throw new RuntimeException(ex);
//            }
//        }
//    }
//
//    public static <T> T readValue(String jsonString, Class<T> tClass) {
//        try {
//            return objectMapper.readValue(jsonString, tClass);
//        } catch (IOException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    private static <C extends Collection<T>, T> C doParseToCollection(
//            String jsonString, Class<C> listClass, Type elementType) {
//        JavaType colType = TypeFactory.defaultInstance()
//                .constructCollectionType(listClass, toJavaType(elementType));
//        return readValue(jsonString, colType);
//    }
//
//    private static <K, V, M extends Map<K, V>> M doParseToMap(
//            String jsonString, Class<M> mapClass, Class<K> keyClass, Class<V> valueClass) {
//        JavaType mapType = TypeFactory.defaultInstance()
//                .constructMapType(mapClass, keyClass, valueClass);
//        return readValue(jsonString, mapType);
//    }
//
//    private static <K, V> Map<K, V> doParseToMap(String jsonString, Type keyType, Type valueType) {
//        JavaType mapType = TypeFactory.defaultInstance()
//                .constructMapType(Map.class, toJavaType(keyType), toJavaType(valueType));
//        return readValue(jsonString, mapType);
//    }
//
//    @SuppressWarnings("TypeParameterUnusedInFormals")
//    private static <T> T readValue(String jsonString, JavaType javaType) {
//        try {
//            return objectMapper.readValue(jsonString, javaType);
//        } catch (IOException ex) {
//            throw new JsonException(ex);
//        }
//    }
//
//    private static JavaType toJavaType(Type type) {
//        JavaType javaType;
//        if (type instanceof JavaType) {
//            javaType = (JavaType) type;
//        } else {
//            // Fixed Generic Type (ParameterizedType)
//            TypeFactory typeFactory = TypeFactory.defaultInstance();
//            if (type instanceof ParameterizedType) {
//                ParameterizedType pType = (ParameterizedType) type;
//                Type[] argTypes = pType.getActualTypeArguments();
//                Type ownerType = pType.getRawType();
//                JavaType[] argJavaTypes = new JavaType[argTypes.length];
//                for (int i = 0; i < argTypes.length; i++) {
//                    argJavaTypes[i] = typeFactory.constructType(argTypes[i]);
//                }
//                javaType = typeFactory.constructSimpleType((Class<?>) ownerType, argJavaTypes);
//            } else {
//                javaType = typeFactory.constructType(type);
//            }
//        }
//        return javaType;
//    }
//
//    private static String object2JsonString(Object input) {
//        String targetJson;
//        if (input instanceof String) {
//            targetJson = (String) input;
//        } else if (input instanceof byte[]) {
//            targetJson = new String((byte[]) input, StandardCharsets.UTF_8);
//        } else {
//            targetJson = input.toString();
//        }
//        return targetJson;
//    }
//
//    private static JsonException rethrow(Object input, Type type, Throwable ex) {
//        String targetJson = object2JsonString(input);
//        return new JsonException(
//                String.format("The target json (%s) cannot parse to %s.", targetJson, type), ex);
//    }
//
//    private static ObjectMapper defaultObjectMapper() {
//        ObjectMapper mapper = new ObjectMapper();
//        mapper.findAndRegisterModules();
//
//        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//        mapper.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
//        mapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
//        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//        mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
//        return mapper;
//    }
//
//    public static void setObjectMapper(@NotNull ObjectMapper objectMapper) {
//        JsonKt.objectMapper = objectMapper;
//        JsonKt.prettyWriter = objectMapper.writerWithDefaultPrettyPrinter();
//    }
//
//    @Component("jsonKtCompanion")
//    public static class Companion implements InitializingBean, DisposableBean {
//        private final ConcurrentMap<Class<?>, ObjectWriter> viewWriters =
//                new MapMaker().initialCapacity(10).makeMap();
//        private ObjectMapper objectMapper;
//
//        public Companion() {
//            objectMapper = defaultObjectMapper();
//        }
//
//        @Override
//        public void afterPropertiesSet() {
//            JsonKt.setObjectMapper(objectMapper);
//            JsonKt.companion = this;
//        }
//
//        @Override
//        public void destroy() {
//            viewWriters.clear();
//        }
//
//        @Autowired(required = false)
//        public void setObjectMapper(ObjectMapper objectMapper) {
//            Assert.notNull(objectMapper);
//            this.objectMapper = objectMapper;
//        }
//    }
//
//    private JsonKt() {}
}
